<?php
/**
 * Smithy PHP library
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * Smithy is a free Zend Framework based PHP library.
 *
 * @category   Smithy
 * @package    Smithy_Model
 * @subpackage Value
 * @copyright  Copyright (c) 2008-2009 Kovács Tamás
 * @license    New BSD License
 * @version    $Id: Abstract.php ktamas $
 */

/**
 * A basic model value class.
 *
 * Defines a Java style value object, that aggregates a
 * Zend_Db_Table_Row_Abstract data source.
 *
 * @author Kovács Tamás
 * @category Smithy
 * @package Smithy_Model
 * @subpackage Value
 */
abstract class Smithy_Model_Value_Abstract
{
    /**
     * The gateway object.
     *
     * @var Smithy_Model_Gateway_Abstract
     */
    protected $_gateway = null;

    /**
     * The datasource object.
     *
     * @var array|Zend_Db_Table_Row_Abstract
     */
    protected $_dataSource = null;


    /**
     * Constructor..
     *
     * @return void
     */
    public function __construct($config, $gateway = null)
    {
        $this->setGateway($gateway)
            ->populate($config);

        $this->init();
    }

    /**
     * Initialize gateway.
     *
     * @return void
     */
    public function init()
    {}

    /**
     *
     * @param array|Zend_Db_Table_Row_Abstract|Zend_Config|Smithy_Model_Value_Abstract $config
     */
    public function populate($config)
    {
        if ($config instanceof Smithy_Model_Value_Abstract) {
            $config = $config->getDataSource();
        }

        if ($config instanceof Zend_Db_Table_Row_Abstract) {
            $this->_dataSource = $config;
        } else {
            if ($config instanceof Zend_Config) {
                $config = $config->toArray();
            }

            if (!is_array($config)) {
                throw new Exception('Config must be an instance of Zend_Config or Zend_Db_Table_Row_Abstract or be an array.');
            }

            $this->_dataSource = $this->getTable()->createRow($config);
        }

        return $this;
    }

    /**
     * Returns the value objects data source.
     *
     * @return array|Zend_Db_Table_Row_Abstract
     */
    public function getDataSource()
    {
        return $this->_dataSource;
    }

    /**
     * Returns the gateway class.
     *
     * @return Smithy_Model_Gateway_Abstract
     */
    public function getGateway()
    {
        if (null === $this->_gateway) {
            $this->_gateway = new Webshop_ProductGateway();
        }
        return $this->_gateway;
    }

    /**
     * Sets the gateway class.
     *
     * @param Smithy_Model_Gateway_Abstract $gateway
     * @return Webshop_Product
     */
    public function setGateway(Smithy_Model_Gateway_Abstract $gateway)
    {
        $this->_gateway = $gateway;
        return $this;
    }

    /**
     * Returns the value object's datasource as an array.
     *
     * @return array
     */
    public function toArray()
    {
        if ($this->_dataSource instanceof Zend_Db_Table_Row_Abstract) {
            return $this->_dataSource->toArray();
        }

        if (is_array($this->_dataSource)) {
            return $this->_dataSource;
        }

        return (array)$this->_dataSource;
    }

    /**
     * Saves the object to the datasource.
     *
     * @return mixed The primary key value(s), as an associative array if the key is compound, or a
                     scalar if the key is single-column.
     */
    public function save()
    {
        return $this->_dataSource->save();
    }

    /**
     * Sets the given property.
     *
     * @return void
     */
    public function __set($name, $value)
    {
        if (is_array($this->_dataSource)) {
            if (array_key_exists($name, $this->_dataSource)) {
                $this->_dataSource[$name] = $value;
            }
        } else {
            $setMethod = 'set' . ucfirst(strtolower($name));
            if (method_exists($this, $setMethod)) {
                call_user_func(
                    array($this, $setMethod),
                    $value
                );
            }

            $this->_dataSource->$name = $value;
        }
    }

    /**
     * Gets the given property.
     *
     * @return mixed
     */
    public function __get($name)
    {
        if (is_array($this->_dataSource)) {
            if (array_key_exists($name, $this->_dataSource)) {
                return $this->_dataSource[$name];
            }
        } else {
            $setMethod = 'get' . ucfirst(strtolower($name));
            if (method_exists($this, $setMethod)) {
                return call_user_func(
                    array($this, $setMethod),
                    null
                );
            }

            return $this->_dataSource->$name;
        }
    }

    /**
     * Checks if a datasource parameter is set.
     *
     * @param string $name
     * @return bool
     */
    public function __isset($name)
    {
        return isset($this->_dataSource->$name);
    }

    /**
     * Calls a method on the $_data object.
     */
    public function __call($name, $arguments)
    {
        return call_user_func_array(
            array($this->_dataSource, $name),
            $arguments
        );
    }

    /**
     * Returns the value object's form.
     *
     * @return Zend_Form
     */
    abstract public function getForm();

    /**
     * Returns the value object's table object.
     *
     * @return Zend_Db_Table
     */
    abstract public function getTable();

    /**
     * Returns the value object's model.
     *
     * @return Smithy_Model_Gateway
     */
    abstract public function getModel();
}
